home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The PC-SIG Library 9
/
The PC-SIG Library on CD ROM - Ninth Edition.iso
/
501_600
/
DISK0579
/
DISK0579.ZIP
/
CHAP15.TXT
< prev
next >
Wrap
Text File
|
1989-12-01
|
30KB
|
709 lines
Chapter 15
ENCAPSULATION & INHERITANCE
Encapsulation is the cornerstone upon which object oriented
programming is built, and without which it would not exist.
We will cover the topic of encapsulation in this chapter in
enough depth to illustrate its use and what it can do for you
in software development. Because there are many new terms in
this chapter, you could very easily become intimidated, and
wish to simply give up on this new topic. You can be assured
that the time spent studying encapsulation will be greatly
rewarded as you apply this new technique in your software
development efforts.
Object oriented programming is not a panacea to solve all of
your software problems, but it is a new and improved way of
programming. In fact it is really more of a software
packaging technology than a new method of programming. You
will find that your software will be easier to write and debug
as you gain experience using this new packaging method. Like
any new endeavor however, it will require some effort on your
part to master these concepts.
OUR FIRST ENCAPSULATION
____________________________________________________________
The example program named ENCAP1.PAS contains ==============
our first example of encapsulation. In order ENCAP1.PAS
to keep it easy to understand, it was kept ==============
very short. This results in a program that
does not illustrate the advantage of using
object oriented programming, but it does give us a start in
the right direction. With this in mind, load ENCAP1.PAS and
we will study the code contained in it.
Line 5 has our first new reserved word, object. This is used
in much the same way that the reserved word record is used,
but it has a much different meaning. An object is permitted
to have not only data embedded within it, but also procedures,
functions, and constructors. Constructors will be described
in detail later. Since data plus procedures and functions can
be grouped together in this fashion, the object is said to be
encapsulated. An object is therefore a group of related data
and the subprograms that operate on that data, all entities
being very closely coupled together.
WHAT IS A METHOD?
____________________________________________________________
A method is a term used with object oriented programming, and
for the time being we will simply say that a method is either
Page 15-1
Encapsulation and Inheritance
a function or a procedure (including a constructor). A method
is therefore a method for doing an operation on some data.
Lines 8 through 10 are method headers and give the pattern for
all calls to these methods which can be used by the compiler
to check for the correct number and types of parameters.
Once again, we promise to discuss the constructor soon. For
the time being, simply think of it as another procedure.
The entire object type definition is given in lines 5 through
11. This object contains two variables named length and
width, each of type integer, and three methods which can be
used to operate on the two variables. In the same manner that
the definition of a type in Pascal does not actually give you
a variable to use, only a pattern, the definition of an object
type does not give you an object. We will declare the objects
when we get to line 30 of this program.
You will note that we are already using new terminology, but
this is necessary. The field of object oriented programming
has its own vocabulary and in order for you to understand
technical articles in this field, you must begin now to learn
the new terminology. It won't be too long until you feel
somewhat comfortable with it.
THE METHOD IMPLEMENTATION
____________________________________________________________
The object type definition describes in detail what we can do
with the object but we must now describe what actions will
take place when each of the methods is called. The
implementation for each method will define the operations for
that method and are defined in lines 13 through 28 of this
example program. The only thing that is really different
about these methods is the way their headers are defined,
namely the inclusion, in the header, of the object type name
Box dotted to the method name. This is required, but we will
wait until the next example program to define why it is
needed.
The observant student will also notice that we are referring
to the object variables within the methods of that object
without the object name dotted to the variable name. This is
because the implied object name is automatically "with"ed to
the variable names within the method implementations, allowing
the variables to be directly referred to within the objects
because of the definition of object oriented programming. It
should be obvious that any mathematics or logical operations
can be done within the implementations of the methods. In
fact, you can perform any legal Pascal operations within the
methods, just like you can in any Pascal function or
procedure. Very short operations were selected here because
Page 15-2
Encapsulation and Inheritance
we wish to illustrate the interfaces to the methods at this
point in the tutorial.
AN INSTANCE OF AN OBJECT
____________________________________________________________
We need another new term at this point. When we use the
object type to declare variables of that type as we do in line
30, we are creating instances of that object type. An
instance is like a variable in conventional Pascal (non object
oriented), except that it can do more and has some very
interesting properties that a simple variable does not have.
In line 30 we have created three instances of the object type
named Box and each has two simple variables associated with
it. Three methods are available which can be called to
operate on these variables. We therefore have three objects
named Small, Medium, and Large. In order to initialize the
values stored within the objects we call the three objects in
lines 34 through 36 to store values in their internal
variables by dotting the name of the object to the name of the
method we wish to call. You will note that this looks like
the same technique we use to refer to the fields of a record.
We display the area of the three boxes in lines 38 through 40
using the same technique used to initialize the values stored,
and the program is complete.
We seem to have accomplished very little with this program
that we could not have more easily accomplished with an even
shorter standard Pascal program, and that is true. This
program is only meant to introduce some of the mechanics of
object oriented programming and additional programs will be
used to illustrate some of the uses of this new technique.
NEW TERMINOLOGY
____________________________________________________________
You may note that we switched terminology halfway through the
above paragraphs. We began by referring to the object types
as object types and calling the variables declared in line 30
instances. Later we began calling the instances objects. In
this tutorial we will refer to the types as object types and
the variables either as objects or instances. This
terminology is consistent with current practice and should
help you learn the new terminology.
Another very important point is the fact that we pass a
message to a method rather than call a subprogram as in
conventional Pascal. The difference is rather subtle, but
there really is a difference as we will see a little later in
this tutorial.
Page 15-3
Encapsulation and Inheritance
WHAT DID WE ACCOMPLISH?
____________________________________________________________
In this program we defined an object type, then declared
several instances of that type, one of which was named Small.
The object named Small has two internal variables that should
only be accessed via its methods, so we will refer to them as
private data points. (Actually, they should be unavailable
to any user outside of the method implementations but Borland
chose not to make them private. It is therefore up to you to
discipline yourself to not refer to them directly.) The
proper way to use the object is to send a message to the
object telling it to do something to itself. In the case of
the Init method, we are telling it to store the two values in
its private variables named length and width, and in the case
of the Get_Area method, we are telling it to give us the
product of its own internally stored width and length which
we can then print out.
Remember that in the beginning of this chapter we said that
object oriented programming is a code packaging technique.
That should help to explain some of the strange things we did
in this program. As we continue through the example programs,
we will see that everything here was done for a reason and you
will eventually learn to use and prefer object oriented
programming methods over the old familiar procedural
programming method you have been using.
Be sure to compile and execute this program to see if it does
what the comments say it will do.
DATA & CODE PROTECTION
____________________________________________________________
The data and methods are protected from outside influence
because they are packaged together with an object. Of even
more importance is the fact that because they were to be
packaged together, they were probably carefully thought out
together during the design stage. This would probably result
in a much more understandable program. The object keeps the
data and methods together and keeps them working in close
synchronization.
An object type is sometimes referred to as an abstract data
type in the technical literature discussing object oriented
programming.
Page 15-4
Encapsulation and Inheritance
MORE ENCAPSULATION
____________________________________________________________
The example program named ENCAP2.PAS uses ================
most of the same techniques as the last ENCAP2.PAS
program but this is much more meaningful ================
since it illustrates one of the simplest
advantages of using object oriented
programming.
In this program, we define two object types in lines 5 through
19, Box and Pole. Each has its own unique kinds of variables
associated with it, and each has three methods that can be
used with these kinds of data. The method definitions in
lines 33 and 44 clearly illustrate why the object name must
be associated with the method name in the method
implementation. This allows you to use the same method name
in more than one object definition. In addition to the two
method definitions named Set_Data given here, we could also
define and use another procedure with the name Set_Data that
was a normal Pascal procedure just like any others we have
used in prior chapters of this tutorial. Using the same
method name in several places is often referred to as name
overloading in object oriented programming terminology.
You will note that in lines 5 through 19 we define the object
types which define what the object will do. In lines 21
through 53 we define the method implementations which define
how we do it. It is assumed that you know enough Pascal at
this point to understand what each method does, so nothing
more will be said about the details of this program.
In lines 55 and 56, we declare several objects of the defined
object types and use some of them in the main program. We can
finally illustrate one of the biggest advantages of object
oriented programming.
We should all agree that it would be silly and meaningless to
multiply the height of one of the poles by the width of a box.
If we were using standard procedural programming with all
variables defined globally, it would be a simple matter to
accidentally write height*width and print out the result
thinking we had a meaningful answer. By encapsulating the
data within the objects, we would have to really work at it
to get that meaningless answer because the system itself would
prevent us from accidentally using the wrong data. This is
true only if we have agreed not to use any of the data
directly but to do all data access through the available
methods.
Encapsulation is a form of information hiding, but it is a
rather weak form of it in TURBO Pascal because, as mentioned
earlier, Borland chose not to make the variables within the
object private. If the variables were defined as private
Page 15-5
Encapsulation and Inheritance
variables, they would be unaccessible outside of the
implementation for the object and the client would be forced
to use only the methods provided by the author of the object
to access the contained data. This would be true information
hiding and would add some degree of protection to the internal
data. It is up to you to never refer to the data within the
object directly as stated by Borland in the OOP GUIDE included
with the compiler.
The careful student will notice that since all data is
carefully tied up within the objects, inadvertent mixing of
the wrong data is impossible provided a few simple rules are
followed as discussed above. Once again, this is such a small
program that it is difficult to see the advantage of going to
all of this trouble. In a larger program, once the objects
are completed, it is a simple matter to use them knowing that
they are debugged and working.
After the data are all printed out, some of the variables are
changed in lines 78 through 80, and the same output statements
are used to reprint the same data so you can observe the
changes.
A FEW RULES ARE NEEDED
____________________________________________________________
As with any new topic, there are a few rules we must follow
to use this new technique. The variables must all be declared
first in the object followed by the method definitions. The
names of all variables within an object must be unique and
may not be repeated as the names of any of the formal
variables in any of the methods. Thus length, width, len, and
wid must be unique as used in lines 6, 7, and 8. The names
of formal variables may be reused in other methods however,
as illustrated in lines 8 and 9, and all names may be reused
in another object. It should be obvious that all object type
names must be unique within a given file and all objects must
have unique names.
All of the above rules are obvious if you spend a little time
thinking about them. They should therefore not be a stumbling
block to anyone with some procedural programming experience.
WHAT IS A CONSTRUCTOR?
____________________________________________________________
It is time to keep our promise and define just what a
constructor is. In this present context, that of simple
objects, the constructor does very little for us, but we will
include one for nearly every object to illustrate its use.
Page 15-6
Encapsulation and Inheritance
The constructor can be named anything desired but it would be
best to stick with the convention and name every constructor
Init as suggested by Borland. The constructor is used to
initialize all values within an object and do any other setup
that must be done to use an object. The constructor should
be called once for every declared object. When we get to the
topic of virtual functions, constructors will be absolutely
required for every object, but for the simple objects we are
using here, they are optional.
It would be best to include a constructor in every object
type, use the constructor to initialize all variables within
the object, and call the constructor once for each instance
of the object type. Until we get to virtual methods, none of
this is required, but it would be good practice to get in the
habit of doing it.
WHAT IS A DESTRUCTOR?
____________________________________________________________
A destructor is another method that can be used for cleanup
when you are finished with an object. It is usually used in
conjunction with dynamic allocation to assure that all
dynamically allocated fields associated with the object are
deallocated prior to leaving the scope of the object. A
destructor is not illustrated in this tutorial but it should
be easy for you to define and use one when you have a need for
one.
OUR FIRST INHERITANCE
____________________________________________________________
Load the example program named INHERIT1.PAS ================
for our first example of a program with INHERIT1.PAS
inheritance. As always, our first encounter ================
with this new topic will be very simple.
In lines 7 through 14 we define a simple object type defining
a vehicle and a few characteristics about the vehicle. We
have the ability to store a few values and read them out in
several ways. Of course, most of the interest is in the
interfaces, so the implementations are purposely kept very
small.
In lines 17 through 35, we declare two additional object types
that use the Vehicle type as a base for the new types as
indicated by the previously defined name Vehicle in
parentheses in the object definitions in lines 17 and 26. The
Vehicle object is said to be the ancestor type and the two new
object types are called descendant types. The descendant
Page 15-7
Encapsulation and Inheritance
types inherit some information from the ancestor types
according to well defined rules. The variables in the
ancestor type are all included within the descendant types and
are available in objects of the descendant types just as if
they had been defined within the descendant types. For that
reason, all variable names must be unique within the ancestor
type and within each of the descendant types. A name can be
reused in one or more descendants however, as is illustrated
in lines 18 and 27 where the variable name Passenger_Load is
used in both object types.
The method names from the ancestor object types can be
repeated in the descendant object types but this has the
effect of overriding the method of the same name in the
ancestor making the ancestor method unavailable for use in
objects of the descendant types. Objects instantiated of the
type Car therefore, have the three methods available in lines
11 through 13 of the ancestor type, the constructor in line
19 which overrides the constructor in line 10 of the ancestor
type, and the function given in line 22. This object
therefore has five different methods to perform its required
operations.
Objects of type Truck have five methods available also, the
two in lines 11 and 12 and the one in line 33. The two in
lines 29 and 34 of the descendant overrides the two in lines
10 and 13 of the ancestor object type.
You should note that even though some of the methods were
overridden in the descendant object type, they do not affect
the ancestor, and instances of the Vehicle type have two
variables and four methods available.
In effect we have an object hierarchy which can be extended
to as many levels as necessary to complete the task at hand.
The most important part of object oriented programming is the
definition of the objects in a meaningful manner, but it is
not something you will learn to do overnight. It will take
a great deal of practice until you can see the objects in any
given project in such a way that a clear solution can be
found. I was somewhat intimidated by the clever examples
found in a classic text on object oriented programming until
I talked to a man that had shared an office with the author
at the time he was writing that particular book. I learned
that what was finally put in the book was at least the fourth
iteration of each problem and in some cases the seventh before
he finally arrived at a good solution. We will have more to
say about this as we progress through this tutorial.
Page 15-8
Encapsulation and Inheritance
HOW DO WE USE THE OBJECTS?
____________________________________________________________
The implementations of the methods are given in lines 39
through 92 and should be self explanatory, except for a few
notable exceptions. You will note that in line 81 we send a
message to the Vehicle.Init method to initialize some data.
A change to the Vehicle type will be reflected in the Truck
type also because of this call. In lines 64 and 65 we are
using some inherited variables just as if they had been
defined as part of the descendant object types.
In lines 96 through 98 we instantiate one of each and send a
message to their constructors in lines 102 through 104 then
print out a few of the stored values.
Lines 113 through 116 are repeated in lines 120 through 123
where they are placed within a with section to illustrate that
the with can be used for the calls to the methods in the same
manner that it is used for accessing the fields of a record.
Any other details of this program can be gleaned by the
diligent student. Be sure to compile and execute this program
so you can verify the given result.
AN OBJECT IN A UNIT
____________________________________________________________
Load the example program named VEHICLES.PAS ================
for an example of the proper way to package VEHICLES.PAS
the object so it can be conveniently reused ================
for another project.
The object type definition is given in the public part of the
unit so it is available to any Pascal program which needs to
use it. The implementation of the methods are hidden in the
implementation part of the unit where they are not directly
available to any calling program. Note that it is also
possible to define a few local methods within the
implementation for use only within the implementation but none
are illustrated here. There is no body to this unit, only the
end statement in line 39 so there is no initialization code
to be executed during loading. It would be perfectly legal
to include an initialization body, but if you do, be sure to
include a constructor to be called once for each object. This
is to prepare you for the use of virtual functions which we
will study in the next chapter.
It will be necessary for you to compile this unit to disk so
it can be used with the last example program in this chapter.
Page 15-9
Encapsulation and Inheritance
ANOTHER OBJECT IN A UNIT
____________________________________________________________
The example program named CARTRUCK.PAS ================
continues the new packaging scheme by CARTRUCK.PAS
including the two descendant object types in ================
its interface after telling the system that
it uses the Vehicles unit.
The remainder of this unit is constructed just like the last
one so nothing more needs to be said about it. Be sure to
compile this unit to disk so it will be available for use with
the next example program.
Note that this unit could have been further divided into two
separate units, one for each object type, but it was felt that
it was important to illustrate that several can be combined
in this manner if desired. In like manner, the last unit
could have been combined with this unit, but once again, it
was desired to illustrate the generality of program
decomposition and packaging.
USING THE OBJECTS DEFINED IN UNITS
____________________________________________________________
Load the program named INHERIT2.PAS for an ================
example that uses the units of the last two INHERIT2.PAS
example programs and is identical to the ================
program named INHERIT1.PAS.
The only difference in these two programs is in the way the
code was packaged. The second way is much more general and
more conducive to good software engineering practices because
it allows separate development of each of the three program
units. Each can be refined independently of the other two and
the overall package can be simpler to debug and maintain. It
should be clear that any changes to the Car object, for
example, will be localized to that single unit and not
scattered all over the software terrain.
AN ARRAY AND A POINTER
____________________________________________________________
Examine the example program named ================
INHERIT3.PAS for an example of the use of a INHERIT3.PAS
pointer to an object and the use of an array ================
of objects.
This program is nearly identical to INHERIT2.PAS except for
the addition of an array of Car type objects named Sedan[1]
to Sedan [3], and the definition of a pointer to the Truck
type object named Semi_Point. Lines 16 and 17 illustrate the
Page 15-10
Encapsulation and Inheritance
initialization of the array of Sedan, and lines 23 through 26
illustrates its use when the data is printed out. An object
is dynamically allocated in line 18 and it is then initialized
in the next line. Its use is illustrated in lines 28 through
40 and it is deallocated in line 41.
TURBO Pascal 5.5 has an extension to the New procedure
allowing the dynamic allocation and the initialization to take
place in the same procedure call. The line
New(Semi_Point, Init(1, 25000.0, 18, 5000.0));
can be used to replace lines 18 and 19 in this program if you
desire to do so.
This program should illustrate that objects can be used with
arrays and pointers just like a record. Be sure to compile
and execute this program.
WHAT IS MULTIPLE INHERITANCE?
____________________________________________________________
Multiple inheritance allows the programmer to inherit data and
methods from two or more ancestor objects. When this is done
however, there is a real problem if there are two variables
or methods of the same name and it is up to the programmer to
somehow define which will be used by the descendent. Some
object oriented programming languages allow multiple
inheritance, but most do not. TURBO Pascal (version 5.5) has
no provision for multiple inheritance, and Borland has made
no indication at this time whether future versions will allow
it.
WHAT SHOULD YOU DO NOW?
____________________________________________________________
You have reached a major point in your excursion of object
oriented programming, because you now have most of the
knowledge you need to do some serious object oriented
programming. The best thing for you to do at this point is
stop studying and get busy programming and using some of these
techniques for your projects. The only topic left is the use
of virtual methods and you can easily defer its use for a long
time.
One point should be made before you begin a serious
programming project. Your first program could have too many
objects and be nearly unreadable unless you strive to use only
a few objects until you gain experience. Define only a few
objects and write the majority of the program in standard
Page 15-11
Encapsulation and Inheritance
procedural programming methods. Add a few more objects to
your next project and as you gain experience, you will feel
very comfortable with the use of objects and your programming
methods will be very clear.
Now is the time to begin using this new knowledge but enter
the water slowly the first time.
PROGRAMMING EXERCISES
____________________________________________________________
1. Modify ENCAP2.PAS in such a way to multiply the height
of the short pole times the length of the medium box and
print the result out. Even though this is possible to
do, it requires you to expend a bit of effort to
accomplish. Remember that you should not use the
components of an object directly, only through use of the
available methods.
2. Add an object named Pick_Up to INHERIT2.PAS of type Truck
and initialize it to some reasonable values. Print out
its loading and efficiency in a manner similar to the
Semi.
Page 15-12